#! /usr/bin/python3

import threading
import datetime

from flask import Flask
from flask import render_template
from flask_socketio import SocketIO
from sqlalchemy import create_engine, desc, event, extract, or_, func, select
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session

from service.data import Data
from service.db import Logger

app = Flask(__name__)
socketio = SocketIO(app)

# logger = None

# eb
Base = declarative_base()
engine = create_engine("postgresql+psycopg2://postgres:1@localhost/logger", isolation_level="READ UNCOMMITTED")
Session = scoped_session(sessionmaker(bind=engine))

# added 2019.06.19
logger = Logger(Session, socketio)

week = ('一', '二', '三', '四', '五', '六', '天')
# 2018.08.19 增加1_2
m_type = {'加工': 'jg', '涂装半成品': 'tb', '涂装成品': 'tc', '亚克力入口': 'yr', '亚克力\
出口': 'yc', '旋压': 'xy', '旋压2': 'xy2', '切帽': 'qm', '正面': 'zm', '热处理1线': 're1', '热处理2线': 're2',
          '铸造1线': 'zz1', '铸造2线': 'zz2', '加工_分立': 'ng', '铸造2线边浇': 'zz3', 'F2加工_分立': 'njg',
          'F2热处理': 're3'}

m_type_2 = ['jg', 'tb', 'tc', 'yr', 'yc', 'xy', 'qm', 'zm', 're1', 're2', 'zz1', 'zz2', 'zz3', 'ng', 'njg', 're3']

_DAY_START = 7  # 白班时间


# 自定义函数

# 读实时数据
def get_realm_data(factory=1):
    ts = datetime.datetime.now()
    time_start = datetime.datetime(ts.year, ts.month, ts.day)
    time_end = time_start + datetime.timedelta(24)

    session = Session()
    jg = session.query(Data).filter(Data.ts > time_start, Data.ts < time_end,
                                    Data.type == '加工', Data.factory == factory).order_by(desc(Data.ts)).first()
    tb = session.query(Data).filter(Data.ts > time_start, Data.ts < time_end,
                                    Data.type == '涂装半成品', Data.factory == factory).order_by(desc(Data.ts)).first()
    tc = session.query(Data).filter(Data.ts > time_start, Data.ts < time_end,
                                    Data.type == '涂装成品', Data.factory == factory).order_by(desc(Data.ts)).first()
    yr = session.query(Data).filter(Data.ts > time_start, Data.ts < time_end,
                                    Data.type == '亚克力入口', Data.factory == factory).order_by(desc(Data.ts)).first()
    yc = session.query(Data).filter(Data.ts > time_start, Data.ts < time_end,
                                    Data.type == '亚克力出口', Data.factory == factory).order_by(desc(Data.ts)).first()
    zz_1 = session.query(Data).filter(Data.ts > time_start, Data.ts < time_end,
                                      Data.type == '铸造1线', Data.factory == factory).order_by(desc(Data.ts)).first()
    session.close()

    c_date = "%d.%d.%d %d:%d 星期%s" % (
        ts.year, ts.month, ts.day, ts.hour, ts.minute, week[ts.weekday()])

    v = {
        'jg': jg.number,
        'tb': tb.number,
        'tc': tc.number,
        'yr': yr.number,
        'yc': yc.number,
        'zz_1': zz_1.number,
        'date': c_date
    }
    return v


# 当天数据总览
# m_type 工序 dt datetime
def data_overview(dt, m_type, factory=1):
    assert type(dt) is datetime.datetime
    assert type(m_type) is str

    _DAY = 7
    _NIGHT = 19

    dt_2 = dt + datetime.timedelta(24)
    is_daytime = False
    if _DAY <= dt.hour < _NIGHT:
        is_daytime = True
    else:
        is_daytime = False

    num_daytime = 0
    num_nighttime = 0

    session = Session()
    # 白天，白班=总数，晚班=0
    if is_daytime:
        try:
            num_daytime = session.query(Data).filter(Data.ts >= dt, Data.ts < dt_2,
                                                     Data.type == m_type).order_by(desc(Data.ts),
                                                                                   Data.factory == factory).first().number
        except:
            pass
        num_nighttime = 0
    else:
        # 晚上，白天=sum(7:00-18:59, <19)， 晚班=消息数，总数=白班+晚班
        dt = datetime.datetime(dt.year, dt.month, dt.day, _DAY)
        dt_2 = dt + datetime.timedelta(hours=12)
        try:
            num_daytime = session.query(Data).filter(Data.ts >= dt, Data.ts < dt_2,
                                                     Data.type == m_type, Data.factory == factory).order_by(
                desc(Data.ts)).first().number
            num_nighttime = session.query(Data).filter(Data.ts >= dt_2,
                                                       Data.ts < dt_2 + datetime.timedelta(hours=12),
                                                       Data.type == m_type, Data.factory == factory).order_by(
                desc(Data.ts)).first().number
        except:
            pass

    session.close()
    return num_daytime, num_nighttime, num_daytime + num_nighttime  # 返回 白班数，夜班数，总数


def get_overview_data():
    ts = datetime.datetime.now()
    dt = datetime.datetime(ts.year, ts.month, ts.day)

    c_date = "%d.%d.%d %d:%d 星期%s" % (
        ts.year, ts.month, ts.day, ts.hour, ts.minute, week[ts.weekday()])

    postions = {'jg': '加工', 'tb': '涂装半成品', 'tc': '涂装成品', 'zm': '正面', 'yr': '亚克力入口',
                'yc': '亚克力出口', 'xy': '旋压', 'qm': '切帽'}
    nums = {}
    for k, v in postions.items():
        d, n, t = data_overview(dt, v)
        nums[k] = (d, n, t,)
    v = {
        'jg': nums['jg'],
        'tb': nums['tb'],
        'tc': nums['tc'],
        'yr': nums['yr'],
        'yc': nums['yc'],
        'xy': nums['xy'],
        'qm': nums['qm'],
        'zm': nums['zm'],
        'date': c_date
    }
    return v


# 优化查询总数
def overview_opt(factory):
    q_type = ['jg', 'tb', 'tc', 'yr', 'yc', 'xy', 'xy2', 'qm', 'zm', 're1', 're2', 'zz1', 'zz2', 'zz3', 'ng']
    if factory == 2:
        q_type = ['xy', 'jg', 'tc', 'njg', 're3', 'zz1', 'zz2']

    data_0 = {x: 0 for x in q_type}
    data_1 = {x: 0 for x in q_type}
    data_2 = {x: 0 for x in q_type}
    # data_0 = {'jg': 0, 'tb': 0, 'tc': 0, 'yr': 0, 'yc': 0, 'xy': 0, 'qm': 0, 'zm': 0}
    # data_1 = {'jg': 0, 'tb': 0, 'tc': 0, 'yr': 0, 'yc': 0, 'xy': 0, 'qm': 0, 'zm': 0}
    # data_2 = {'jg': 0, 'tb': 0, 'tc': 0, 'yr': 0, 'yc': 0, 'xy': 0, 'qm': 0, 'zm': 0}

    ts = datetime.datetime.now()
    dt = datetime.datetime(ts.year, ts.month, ts.day, _DAY_START)  # 7:00
    if 0 <= ts.hour < _DAY_START:
        dt = dt + datetime.timedelta(days=-1)
    # 今天数据
    d_1 = get_one_day(dt, factory)  # 0 白班  1 总数 False 今天

    for d in d_1[0]:  # 白班
        data_0[m_type[d.Data.type]] = d.Data.number

    for d in d_1[1]:  # 总数
        data_1[m_type[d.Data.type]] = d.Data.number

    for t in q_type:  # 夜班
        if data_1[t] > data_0[t]:
            data_2[t] = data_1[t] - data_0[t]

    # 昨天数据
    data_10 = {x: 0 for x in q_type}
    data_11 = {x: 0 for x in q_type}
    data_12 = {x: 0 for x in q_type}
    # data_10 = {'jg': 0, 'tb': 0, 'tc': 0, 'yr': 0, 'yc': 0, 'xy': 0, 'qm': 0, 'zm': 0}
    # data_11 = {'jg': 0, 'tb': 0, 'tc': 0, 'yr': 0, 'yc': 0, 'xy': 0, 'qm': 0, 'zm': 0}
    # data_12 = {'jg': 0, 'tb': 0, 'tc': 0, 'yr': 0, 'yc': 0, 'xy': 0, 'qm': 0, 'zm': 0}

    dt = dt + datetime.timedelta(days=-1)
    d_2 = get_one_day(dt, factory)  # True 昨天
    for d in d_2[0]:
        data_10[m_type[d.Data.type]] = d.Data.number

    for d in d_2[1]:
        data_11[m_type[d.Data.type]] = d.Data.number

    for t in q_type:
        # if data_11[t] > data_10[t]:
        data_12[t] = abs(data_11[t] - data_10[t])

    v_0 = {}
    v_1 = {}
    for t in q_type:
        v_0[t] = (data_0[t], data_2[t], data_1[t])
        v_1[t] = (data_10[t], data_12[t], data_11[t])

    # today = {
    #     'jg': v_0['jg'],
    #     'tb': v_0['tb'],
    #     'tc': v_0['tc'],
    #     'yr': v_0['yr'],
    #     'yc': v_0['yc'],
    #     'xy': v_0['xy'],
    #     'qm': v_0['qm'],
    #     'zm': v_0['zm'],
    # }
    today = {x: v_0[x] for x in q_type}
    # yesterday = {
    #     'jg_1': v_1['jg'],
    #     'tb_1': v_1['tb'],
    #     'tc_1': v_1['tc'],
    #     'yr_1': v_1['yr'],
    #     'yc_1': v_1['yc'],
    #     'xy_1': v_1['xy'],
    #     'qm_1': v_1['qm'],
    #     'zm_1': v_1['zm'],
    # }
    yesterday = {x + '_1': v_1[x] for x in q_type}

    c_date = "%d.%02d.%02d %02d:%02d 星期%s" % (
        ts.year, ts.month, ts.day, ts.hour, ts.minute, week[ts.weekday()])

    return today, yesterday, c_date


# 取1天数据
def get_one_day(dt, factory=1):
    session = Session()

    day_start = dt
    day_end = dt + datetime.timedelta(hours=12)
    night_start = day_end  # 夜班，昨晚19点
    night_end = night_start + datetime.timedelta(hours=12)  # 夜班，今早7点

    # 求7:00-1day 7:00
    rows_day = session.query(Data, func.max(Data.number).over(order_by=desc(Data.ts), partition_by=Data.type)) \
        .filter(Data.ts >= day_start, Data.ts < day_end, Data.factory == factory).distinct(Data.type).all()
    rows_total = session.query(Data, func.row_number().over(order_by=desc(Data.ts), partition_by=Data.type)) \
        .filter(Data.ts >= night_start, Data.ts < night_end, Data.factory == factory).distinct(Data.type).all()

    # 当前在白班内，总数=白班数
    ts = datetime.datetime.now()
    if day_start <= ts < day_end:
        rows_total = rows_day

    session.close()
    return rows_day, rows_total


# 监听数据变化
@event.listens_for(Session, 'after_commit')
def update_index(session):
    # value = get_realm_data()
    # if logger is not None:
    #     socketio.emit('index_data', logger.get_temp())
    pass


# socket 监听
@socketio.on('evt_detail')
def handle_my_custom_event(json):
    print('received json: ' + str(json))
    if json['type'] == 'msg_jg':
        return render_template('detail_days.html')


@socketio.on('evt_index')
def handle_my_index(json):
    print(json)
    # socketio.emit('index_data', {'factory': 2, 'xy': 2000})


# 路由
# 首页
@app.route('/')
def index():
    # v = get_realm_data()
    # v = get_overview_data()
    v_today, v_yesterday, c_date = overview_opt(1)
    v_today_f2, v_yesterday_f2, _ = overview_opt(2)
    return render_template('index.html', **v_today, **v_yesterday, f2_today=v_today_f2, f2_yesterday=v_yesterday_f2,
                           date=c_date)


# 铸造
@app.route('/zz')
def zz():
    v_today, v_yesterday, c_date = overview_opt(1)
    return render_template('zz.html', **v_today, **v_yesterday,
                           date=c_date)


# 月
@app.route('/pos/<m_type>/month/<timestamp>/factory/<factory>')
def overview_month(m_type, timestamp, factory):
    ts = datetime.datetime.now()
    if timestamp != '0':
        ts = datetime.datetime.fromtimestamp(int(timestamp))

    year = ts.year
    month = ts.month
    datetime_picker = "%d-%d-%d" % (ts.year, ts.month, ts.day)
    data_day = {}
    # day_count = ts.

    session = Session()
    for i in range(1, 32):
        # 19:00至次日7:00
        try:
            dt = datetime.datetime(year, month, i, _DAY_START)
        except ValueError:
            break
        dt_2 = dt + datetime.timedelta(hours=24)
        d = session.query(Data) \
            .filter(Data.ts >= dt, Data.ts < dt_2, Data.type == m_type, Data.factory == factory) \
            .order_by(desc(Data.ts)) \
            .first()

        if d is not None:
            data_day[str(i)] = d.number
        else:
            data_day[str(i)] = 0

        session.close()
    return render_template('detail_months.html', pos=m_type, data=data_day, datetime_picker=datetime_picker,
                           month=timestamp, factory=factory)


# 小时
@app.route('/pos/<m_type>/day/<timestamp>/factory/<factory>')
def detail_days(m_type, timestamp, factory):
    is_today = False
    if timestamp == '0':
        ts = datetime.datetime.now()
        is_today = True
    else:
        ts = datetime.datetime.fromtimestamp(int(timestamp))
        time_delta = datetime.datetime.now() - ts
        if time_delta < datetime.timedelta(hours=24):  # timestamp 今天
            is_today = True

    dt = datetime.datetime(ts.year, ts.month, ts.day, _DAY_START)  # 从7:00开始---第2天6:00
    time_scope = '%02d.%02d.%02d时' % (dt.month, dt.day, dt.hour)

    # 早上7点內，天数减掉1天
    if is_today and 0 <= datetime.datetime.now().hour < 7:
        dt = dt + datetime.timedelta(days=-1)

    dt_2 = dt + datetime.timedelta(hours=1)
    datetime_picker = "%d-%d-%d" % (ts.year, ts.month, ts.day)
    hours = {}

    session = Session()

    # 循环24次
    for i in range(0, 24):
        records = session.query(Data).filter(Data.ts >= dt, Data.ts < dt_2, Data.type == m_type,
                                             Data.factory == factory) \
            .order_by(desc(Data.ts)).all()
        if len(records) > 0:
            if records[0].number < records[len(records) - 1].number:  # // 跨天
                amount = records[0].number
            else:
                amount = records[0].number - records[len(records) - 1].number
        else:
            amount = 0
        hours["%02d" % dt.hour] = amount
        dt = dt_2
        dt_2 = dt_2 + datetime.timedelta(hours=1)
    # print(hours)
    time_scope = time_scope + '至 %02d.%02d.%02d时' % (dt_2.month, dt_2.day, dt_2.hour - 1)
    session.close()
    # 返回的数据
    v = {
        'pos': m_type,
        'hours': hours,
        'datetime_picker': datetime_picker,
        'day': timestamp,
        'time_scope': time_scope,
        'factory': factory
    }
    return render_template('detail_days.html', **v)


# 分钟
@app.route('/pos/<m_type>/hour/<hour>/<timestamp>/factory/<factory>')
def detail_hours(m_type, hour, timestamp, factory):
    ts = datetime.datetime.now()
    if timestamp != '0':
        ts = datetime.datetime.fromtimestamp(int(timestamp))

    dt = datetime.datetime(ts.year, ts.month, ts.day)
    _, delta = hour.split('_')
    dt = dt + datetime.timedelta(hours=int(delta))
    dt_2 = dt + datetime.timedelta(hours=1)

    result = []

    session = Session()
    records = session.query(Data).filter(Data.ts >= dt, Data.ts < dt_2, Data.type == m_type, Data.factory == factory) \
        .order_by(desc(Data.ts)).all()
    session.close()
    for i, r in enumerate(records):
        ts = r.ts
        t = '%02d:%d:%d' % (ts.hour, ts.minute, ts.second)
        result.append({'idx': i, 'num': r.number, 'created': t})
    m_time = '%d-%02d-%d %d时' % (dt.year, dt.month, dt.day, dt.hour)
    return render_template("detail_hours.html", pos=m_type, records=result, time=m_time, day=timestamp, factory=factory)


# 压力
@app.route('/p')
def get_pressure():
    return render_template('pressure.html')


@app.route('/p_data')
def get_pressure_data():
    return logger.get_history_pressure()


if __name__ == '__main__':
    # app.run()
    # logger = Logger(Session, socketio)
    # threading.Thread(target=logger.connect_mqtt, args=()).start()
    # add 2019.06.19
    logger.connect_mqtt()
    socketio.run(app, host='0.0.0.0', port=8086)
